import { _decorator, Component, Node } from 'cc';
import { Global } from '../../../../script/Global';
import { GameSocket } from '../../../../script/socket/GameSocket';
import { WzqProto } from './WzqProto';
import { SC_WZQ_QUERY, SC_WZQ_DOWN_PIECE, SC_WZQ_GAME_SETTLE, SC_WZQ_GAME_START, SC_WZQ_PLAYER_ENTER, SC_WZQ_PLAYER_EXIT, SC_WZQ_READY, SC_WZQ_UNREADY, IWZQ_PLAYER } from 'db://assets/proto/proto';
import { show_dialog, show_hint } from 'db://assets/sgame/ui/SUI';
import { WzqPlayer } from './WzqPlayer';
import { Graphics } from 'cc';
import { UITransform } from 'cc';
import { Size } from 'cc';
import { WzqMapItem } from './WzqMapItem';
import { WzqGameStatus, WzqHint } from './WzqConst';
import { llog } from 'db://assets/sgame/logger/Logger';
import { Vec3 } from 'cc';
const { ccclass, property } = _decorator;

interface WzqMap {
    [key: number]: {
        [key: number]: WzqMapItem;
    }
}

@ccclass('WzqGame')
export class WzqGame extends Component {
    private gameSocket: GameSocket;
    private playersNode: Node;
    // 相对座位号 -> player
    private players: { [k: number]: WzqPlayer } = [];
    // 绝对座位号 -> player
    private playersByAbsSeat: { [k: number]: WzqPlayer } = [];
    private graphics: Graphics;
    private mapNode: Node;
    private mapItemPrefab: Node;

    private static X_COUNT: number = 10;
    private static Y_COUNT: number = 10;
    private static PIECE_X: number = 60;
    private static PIECE_Y: number = 60;
    private static SEAT_COUNT: number = 2;

    private static GRAPHIC_WIDTH: number = 10;
    private _gameStatus: WzqGameStatus = WzqGameStatus.READYING;

    private _mySeat: number = 0;
    private _curOpSeat: number = 0;
    public get isMyTurn(): boolean {
        return this._mySeat == this._curOpSeat;
    }

    private mapItems: WzqMap = {};

    protected onLoad(): void {
        this.playersNode = this.node.Child("players");
        for (const node of this.playersNode.children) {
            this.players[parseInt(node.name)] = node.Component(WzqPlayer);
        }

        this.graphics = this.node.Component("map", Graphics);
        this.mapNode = this.graphics.node.Child("map");
        this.mapItemPrefab = this.mapNode.Child("item");
        this.gameSocket = Global.gameSocket;
    }

    protected onEnable(): void {
        this.gameSocket.on(WzqProto.WZQ_PLAYER_ENTER, (data: SC_WZQ_PLAYER_ENTER) => {
            this.playerEnter(data.player, data.seat);
        });

        this.gameSocket.on(WzqProto.WZQ_PLAYER_EXIT, (data: SC_WZQ_PLAYER_EXIT) => {
            this.playerExit(data.seat);
        });

        this.gameSocket.on(WzqProto.WZQ_QUERY, this.queryCb, this);
        this.gameSocket.on(WzqProto.WZQ_READY, this.readyCb, this);
        this.gameSocket.on(WzqProto.WZQ_UNREADY, this.unreadyCb, this);
        this.gameSocket.on(WzqProto.WZQ_GAME_START, this.gameStart, this);
        this.gameSocket.on(WzqProto.WZQ_DOWN_PIECE, this.downPieceCb, this);
        this.gameSocket.on(WzqProto.WZQ_GAME_SETTLE, this.gameSettle, this);
        this.gameSocket.send(WzqProto.WZQ_QUERY);
    }

    protected onDisable(): void {
        this.gameSocket.off(WzqProto.WZQ_QUERY, this.queryCb, this);
        this.gameSocket.off(WzqProto.WZQ_READY, this.readyCb, this);
        this.gameSocket.off(WzqProto.WZQ_UNREADY, this.unreadyCb, this);
        this.gameSocket.off(WzqProto.WZQ_GAME_START, this.gameStart, this);
        this.gameSocket.off(WzqProto.WZQ_DOWN_PIECE, this.downPieceCb, this);
        this.gameSocket.off(WzqProto.WZQ_GAME_SETTLE, this.gameSettle, this);
    }

    protected start(): void {
        // 初始化棋盘
        this.init();
    }

    private init() {
        this.graphics.clear();
        // this.graphics.rect(0, 0, 300, 300);
        const maxX = WzqGame.PIECE_X * (WzqGame.X_COUNT / 2) + WzqGame.GRAPHIC_WIDTH * (WzqGame.X_COUNT / 2);
        const minX = -maxX;

        const maxY = WzqGame.PIECE_Y * (WzqGame.Y_COUNT / 2) + WzqGame.GRAPHIC_WIDTH * (WzqGame.Y_COUNT / 2);
        const minY = -maxY;
        this.graphics.node.getComponent(UITransform).setContentSize(new Size(maxX - minX, maxY - minY));
        for (let x = 0; x <= WzqGame.X_COUNT; x++) {
            let xx = minX + x * (WzqGame.PIECE_X + WzqGame.GRAPHIC_WIDTH);
            this.graphics.moveTo(xx, maxY);
            this.graphics.lineTo(xx, minY);
        }

        for (let y = 0; y <= WzqGame.Y_COUNT; y++) {
            let yy = minY + y * (WzqGame.PIECE_Y + WzqGame.GRAPHIC_WIDTH);
            this.graphics.moveTo(minX, yy);
            this.graphics.lineTo(maxX, yy);
        }

        for (let x = 0; x < WzqGame.X_COUNT; x++) {
            let curX = minX + x * (WzqGame.PIECE_X + WzqGame.GRAPHIC_WIDTH) + WzqGame.GRAPHIC_WIDTH / 2;
            this.mapItems[x + 1] = {};
            for (let y = 0; y < WzqGame.Y_COUNT; y++) {
                let node = this.mapItemPrefab.Copy(this.mapNode);
                node.active = true;
                node.OnClick(() => {
                    if (this._gameStatus == WzqGameStatus.GAMING && this.isMyTurn) {
                        this.gameSocket.send(WzqProto.WZQ_DOWN_PIECE, { x: x + 1, y: y + 1 });
                    }
                });

                this.mapItems[x + 1][y + 1] = node.Component(WzqMapItem);
                node.setPosition(curX, minY + y * (WzqGame.PIECE_Y + WzqGame.GRAPHIC_WIDTH) + WzqGame.GRAPHIC_WIDTH / 2);
            }
        }

        this.graphics.stroke();
    }

    private queryCb(data: SC_WZQ_QUERY) {
        this.node.LabelChild("roomId", `房间号: ${data.roomId}`);
        // owner = roomData.owner,
        this._gameStatus = data.gameStatus;
        this._mySeat = data.seat;
        if (this._mySeat == 2) {
            this.mapNode.DORotateToZ(0.1, 180).start();
        }

        let players = data.players;
        for (const seat in players ?? {}) {
            this.playerEnter(players[seat], parseInt(seat));
        }

        if (data.gameStatus == WzqGameStatus.READYING) {
            for (const seat of data.readySeats ?? []) {
                this.playersByAbsSeat[seat].ready();
            }
        } else if (data.gameStatus == WzqGameStatus.GAMING) {
            this._curOpSeat = data.curOpSeat
            for (const x in data.map) {
                for (const y in data.map[x]) {
                    if (data.map[x][y]) {
                        this.mapItems[x][y].downPiece(data.map[x][y] == this._mySeat);
                    }
                }
            }
        }
    }

    private playerEnter(player: IWZQ_PLAYER, seat: number) {
        let offset = seat - this._mySeat;
        if (offset < 0) {
            offset += WzqGame.SEAT_COUNT;
        }

        // 相对座位(玩家位置就是1)
        let relatSeat: number = 1 + offset;
        this.players[relatSeat].player = player;
        if (player.ready) {
            this.players[relatSeat].ready();
        }

        this.playersByAbsSeat[seat] = this.players[relatSeat];
    }

    private playerExit(seat: number) {
        this.playersByAbsSeat[seat].playerExit();
    }

    private readyCb(data: SC_WZQ_READY) {
        this.playersByAbsSeat[data.seat].ready();
    }

    private unreadyCb(data: SC_WZQ_UNREADY) {
        this.playersByAbsSeat[data.seat].unready();
    }

    // 开始游戏
    private gameStart(data: SC_WZQ_GAME_START) {
        show_hint("游戏开始");
        this._gameStatus = WzqGameStatus.GAMING;
        this._curOpSeat = data.curOpSeat;
        for (let seat in this.playersByAbsSeat) {
            this.playersByAbsSeat[seat].startGame();
        }

        this.playersByAbsSeat[data.curOpSeat].startOp();
    }

    private downPieceCb(data: SC_WZQ_DOWN_PIECE) {
        if (data.code) {
            show_hint(WzqHint.DOWN_PIECE_RESULT[data.code]);
            return;
        }

        let piece = data.piece;
        this.mapItems[piece.x][piece.y].downPiece(this._curOpSeat == this._mySeat);
        this.playersByAbsSeat[this._curOpSeat].stopOp();
        if(data.nextOpSeat) {
            this._curOpSeat = data.nextOpSeat;
            this.playersByAbsSeat[this._curOpSeat].startOp();
        }
    }

    private resetGame() {
        this._gameStatus = WzqGameStatus.READYING;

        for (let x = 1; x <= WzqGame.X_COUNT; x++) {
            for (let y = 1; y <= WzqGame.Y_COUNT; y++) {
                this.mapItems[x][y].downPiece(false);
            }
        }
    }

    // 游戏结算
    private gameSettle(data: SC_WZQ_GAME_SETTLE) {
        show_dialog(`游戏结束, 胜者: ${this.playersByAbsSeat[data.winner].roomPlayer.playerInfo.name}`, () => {
            this.resetGame();
        });
    }
}
